using System;
using System.Runtime.InteropServices;
using System.Collections;
using System.Collections.Generic;

namespace Jonathan.SharpDB
{
    #region - Database Messages -

    /// <summary>
    /// Database Messages...
    /// </summary>
    public enum DBMessage
    {
		SUCCESS,
		INVALID_DATABASE,
		INVALID_TABLE_NAME,
        TABLE_EXISTS,
        TABLE_DOES_NOT_EXIST,
        COLUMN_EXISTS,
        UNKNOWN_QUERY,
        QUERY_ERROR,
        INCORRECT_QUERY_TYPE,
        COLUMN_IN_QUERY,
        COLUMN_ROW_NUMBER_MISMATCH,
        NO_QUERY_DATA
    }

    #endregion

    #region - Column Type -

    /// <summary>
    /// SharpDB Supported Column Types...
    /// </summary>
    public enum ColumnType
    {
        STRING,
        INT,
        DECIMAL,
        DATETIME,
        STREAM
    }

    #endregion

    #region - Table Status -

    /// <summary>
    /// Status of Table...
    /// </summary>
    internal enum TableStatus
    {
        DATA_NOT_READ,
        DATA_READ,
        DATA_CHANGED,
        DATA_OK
    }

    #endregion

    #region - Query Type -

    /// <summary>
    /// Types of Queries to perform...
    /// </summary>
    public enum QueryType
    {
        SELECT,
        INSERT,
        DELETE,
        CREATE,
        UPDATE,
        DROP
    }

    #endregion

    #region - Operator Types -

    /// <summary>
    /// Operator Types...
    /// </summary>
    public enum Operator
    {
		/// <summary>
		/// Equals Operator (==).
		/// </summary>
        EQUALS,
		/// <summary>
		/// Does not Equal Operator (!=).
		/// </summary>
        DOES_NOT_EQUAL,
		/// <summary>
		/// Greater Than Operator (>).
		/// </summary>
        GREATER_THAN,
		/// <summary>
		/// Greater Than or Equal Operator (>=).
		/// </summary>
        GREATER_THAN_OR_EQUAL,
		/// <summary>
		/// Less Than Operator (>).
		/// </summary>
        LESS_THAN,
		/// <summary>
		/// Less Than or Equal Operator (>=).
		/// </summary>
        LESS_THAN_OR_EQUAL,
		/// <summary>
		/// Like Operator - is the second value any where in the first - case-insensitive.
		/// </summary>
        LIKE,
		/// <summary>
		/// Like Operator - is the second value any where in the first - case-sensitive.
		/// </summary>
        LIKE_EXACT
    }

    #endregion

    #region - Sort Direction -

    /// <summary>
    /// Direction to Sort...
    /// </summary>
    public enum SortDirection
    {
		/// <summary>
		/// Sort Ascending.
		/// </summary>
        ASCENDING,
		/// <summary>
		/// Sort Decending
		/// </summary>
        DESCENDING
    }

    #endregion

	/// <summary>
	/// A Class with common static methods for SharpDB.
	/// </summary>
    public class Common
	{

		#region -= Check Equal =-

		/// <summary>
		/// Checks if the two values are equal.
		/// </summary>
		/// <param name="type">Type to check.</param>
		/// <param name="val1">First Object to check</param>
		/// <param name="val2">Second Object to Check</param>
		/// <returns></returns>
        public static bool CheckEqual(ColumnType type, object val1, object val2)
        {
            switch (type)
            {
                case ColumnType.STRING:
                    return (val1.ToString() == val2.ToString());
                case ColumnType.INT:
                    return (Convert.ToInt32(val1) == Convert.ToInt32(val2));
                case ColumnType.STREAM:
                    return false;
                case ColumnType.DECIMAL:
                    return (Convert.ToDecimal(val1) == Convert.ToDecimal(val2));
                case ColumnType.DATETIME:
                    return (val1.ToString() == val2.ToString());
            }

            return false;
		}

		#endregion

		#region -= Get Column Index =-

		/// <summary>
        /// Gets the Index of a Column...
        /// </summary>
        /// <param name="colName">Name of Column.</param>
		/// <param name="columns">Column List.</param>
        /// <returns>Index of Column.</returns>
        public static int GetColumnIndex(string colName, List<Column> columns)
        {
            for (int a = 0; a < columns.Count; a++)
            {
                Column col = columns[a];
                if (colName.Equals(col.ColumnName, StringComparison.CurrentCultureIgnoreCase))
                {
                    return a;
                }
            }

            return -1;
		}

		#endregion

		#region - Check Row Match -

		/// <summary>
        /// Check to see if the given row matches the query...
        /// </summary>
        /// <param name="row">Row</param>
		/// <param name="columns">Column List</param>
        /// <param name="cols">Where Columns</param>
        /// <param name="opers">Where Operators</param>
        /// <param name="data">Where Values</param>
        /// <returns>True if row satisfies query.</returns>
        public static bool CheckRowMatch(ArrayList row, List<Column> columns, List<string> cols, List<Operator> opers, ArrayList data)
        {
            int found = 0;
            for (int b = 0; b < cols.Count; b++)
            {
                int colIndex = Common.GetColumnIndex((string)cols[b], columns);
                if (colIndex != -1)
                {
                    //ArrayList row = (ArrayList)this.m_Rows[a];
                    switch (opers[b])
                    {
                        #region - Equals -
                        case Operator.EQUALS:
                            if (Common.CheckEqual(columns[colIndex].ColumnType, row[colIndex], data[b]))
                            {
                                found++;
                            }
                            break;
                        #endregion
                        #region - Not Equal -
                        case Operator.DOES_NOT_EQUAL:
                            if (!Common.CheckEqual(columns[colIndex].ColumnType, row[colIndex], data[b]))
                            {
                                found++;
                            }
                            break;
                        #endregion
                        #region - Greater Than -
                        case Operator.GREATER_THAN:
                            if (columns[colIndex].ColumnType == ColumnType.INT)
                            {
                                if ((int)row[colIndex] > (int)data[b])
                                {
                                    found++;
                                }
                            }
                            else if (columns[colIndex].ColumnType == ColumnType.DECIMAL)
                            {
                                if ((decimal)row[colIndex] > (decimal)data[b])
                                {
                                    found++;
                                }
                            }
                            break;
                        #endregion
                        #region - Greater Than or Equal -
                        case Operator.GREATER_THAN_OR_EQUAL:
                            if (columns[colIndex].ColumnType == ColumnType.INT)
                            {
                                if ((int)row[colIndex] >= (int)data[b])
                                {
                                    found++;
                                }
                            }
                            else if (columns[colIndex].ColumnType == ColumnType.DECIMAL)
                            {
                                if ((decimal)row[colIndex] >= (decimal)data[b])
                                {
                                    found++;
                                }
                            }
                            break;
                        #endregion
                        #region - Less Than -
                        case Operator.LESS_THAN:
                            if (columns[colIndex].ColumnType == ColumnType.INT)
                            {
                                if ((int)row[colIndex] < (int)data[b])
                                {
                                    found++;
                                }
                            }
                            else if (columns[colIndex].ColumnType == ColumnType.DECIMAL)
                            {
                                if ((decimal)row[colIndex] < (decimal)data[b])
                                {
                                    found++;
                                }
                            }
                            break;
                        #endregion
                        #region - Less Than or Equal -
                        case Operator.LESS_THAN_OR_EQUAL:
                            if (columns[colIndex].ColumnType == ColumnType.INT)
                            {
                                if ((int)row[colIndex] <= (int)data[b])
                                {
                                    found++;
                                }
                            }
                            else if (columns[colIndex].ColumnType == ColumnType.DECIMAL)
                            {
                                if ((decimal)row[colIndex] <= (decimal)data[b])
                                {
                                    found++;
                                }
                            }
                            break;
                        #endregion
                        case Operator.LIKE:
                            if (columns[colIndex].ColumnType == ColumnType.STRING)
                            {
                                if (row[colIndex].ToString().ToLower().IndexOf(data[b].ToString().ToLower()) != -1)
                                {
                                    found++;
                                }
                            }
                            break;
                        case Operator.LIKE_EXACT:
                            if (columns[colIndex].ColumnType == ColumnType.STRING)
                            {
                                string[] str = row[colIndex].ToString().Split(' ');
                                for (int z = 0; z < str.Length; z++)
                                {
                                    if (str[z].Equals(data[b].ToString()))
                                    {
                                        found++;
                                        break;
                                    }
                                }
                            }
                            break;
                    }
                }
            }

            if (found == cols.Count)
            {
                return true;
            }

            return false;
        }

        #endregion
    }
}
